package com.tsmti.webservice.util;

import org.apache.log4j.Logger;
import org.apache.poi.ss.formula.functions.T;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Package：com.tsmti.core.util
 * @Class：RedisUtils
 * @Description： TODO
 * @Author：zcw
 * @Date：Created in 2018/3/27 11:05
 * @Company:
 * @Version：
 * @Modified By:
 */
public class RedisUtils {
    private static JedisPool jedisPool;

    @Resource(name = "jedisPool")
    public synchronized void setJedisPool(JedisPool jedisPool) {
        RedisUtils.jedisPool = jedisPool;
    }


    private static Logger logger = Logger.getLogger(RedisUtils.class);
    private static final String RESULT_OK = "OK";
    private static Jedis getJedis()  {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return  jedis;
        } catch (JedisConnectionException e) {
            logger.error("获取Redis 异常", e);
            throw e;
        }
    }


    /**
     * 保存对象到Redis 对象不过期
     *
     * @param key    待缓存的key
     * @param object 待缓存的对象
     * @return 返回是否缓存成功
     */
    public static boolean setObject(String key, Object object) throws Exception {
        return setObject(key, object, -1);
    }

    /**
     * 保存对象到Redis 并设置超时时间
     *
     * @param key     缓存key
     * @param object  缓存对象
     * @param timeout 超时时间
     * @return 返回是否缓存成功
     * @throws Exception 异常上抛
     */
    public static boolean setObject(String key, Object object, int timeout) throws Exception {
        String value = SerializeUtils.serialize(object);
        boolean result = false;
        try {
            //为-1时不设置超时时间
            if (timeout != -1) {
                result = setString(key,value,timeout);
            } else {
                result = setString(key,value);
            }
        } catch (Exception e) {
            throw e;
        }
        return  result;
    }

    public static  boolean setObject(String cacheName,String key, Object object) throws Exception {
        Map<String,Object> map =  (Map<String, Object>)  getObject(cacheName);
        map.put(key,object);
        return setObject(cacheName, map, -1);
    }

    public static  boolean removeObject(String cacheName,String key, Object object) throws Exception {
        boolean flag = false;
        try {
            Map<String,Object> map =  (Map<String, Object>)  getObject(cacheName);
            Iterator<String> iterator = map.keySet().iterator();
            while(iterator.hasNext()){
                String iteratorKey = (String) iterator.next();
                if(key.equals(iteratorKey)){
                    iterator.remove();
                }
            }
            flag = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 从Redis中获取对象
     *
     * @param key 待获取数据的key
     * @return 返回key对应的对象
     */
    public static Object getObject(String key) throws Exception {
        Object object = null;
        try {
            String serializeObj = getString(key);
            if (null == serializeObj || serializeObj.length() == 0) {
                object = null;
            } else {
                object = SerializeUtils.deserialize(serializeObj);
            }
        }  catch (Exception e) {
            throw e;
        }
        return object;
    }

    public static <T> T getObject(String cacheName,String key) throws Exception {
        T object = null;
        try {
            String serializeObj = getString(cacheName);
            if (null == serializeObj || serializeObj.length() == 0) {
                object = null;
            } else {
                Map<String,T> map = (Map<String,T>)SerializeUtils.deserialize(serializeObj);
                if(map !=null && map.size() >0){
                    return map.get(key);
                }
            }
        }  catch (Exception e) {
            throw e;
        }
        return object;
    }

    /**
     * 缓存String类型的数据,数据不过期
     *
     * @param key   待缓存数据的key
     * @param value 需要缓存的额数据
     * @return 返回是否缓存成功
     */
    public static boolean setString(String key, String value) throws Exception {
        return setString(key, value, -1);
    }

    /**
     * 缓存String类型的数据并设置超时时间
     *
     * @param key     key
     * @param value   value
     * @param timeout 超时时间
     * @return 返回是否缓存成功
     */
    public static boolean setString(String key, String value, int timeout) throws Exception {
        String result;
        Jedis jedis = null;
        try {
            jedis = getJedis();
            result = jedis.set(key, value);
            if (timeout != -1) {
                jedis.expire(key, timeout);
            }
            if (RESULT_OK.equals(result)) {
                return true;
            } else {
                return  false;
            }
        } catch (Exception e){
            throw  e;
        } finally {
            releaseRedis(jedis);
        }
    }

    /**
     * 获取String类型的数据
     *
     * @param key 需要获取数据的key
     * @return 返回key对应的数据
     */
    @SuppressWarnings("deprecation")
    public static  String getString(String key) throws Exception {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } catch (Exception e) {
            throw e;
        } finally {
            releaseRedis(jedis);
        }
    }

    /**
     * Jedis 对象释放
     * @param jedis
     */
    public static void releaseRedis(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }


    /**
     * 删除缓存中的数据
     *
     * @param key 需要删除数据的key
     * @return 返回是否删除成功
     */
    public static boolean del(String key) throws Exception {
        Long num;
        Jedis jedis = null;
        boolean result = false;
        try {
            jedis = getJedis();
            num = jedis.del(key);
            if (num.equals(1L)) {
                result = true;
            }
        } catch (Exception e) {
            throw  e;
        } finally {
            releaseRedis(jedis);
        }
        return result;
    }

    /***
     * 设置缓存 ，并将list转为map
     * @param key
     * @param fieldName
     * @param list
     * @param <T>
     */
    public static <T>  Map<String,T> setRedisToMap(String key,String fieldName,List<T> list){
        Map<String,T> map = new HashMap<>(16);
        try {
            for(Object o:list){
                String value =  ConvertUtil.null2String(ReflectionUtils.getFieldValue(o,fieldName));
                map.put(value,(T)o);
            }
            setObject(key,map);
        }catch (Exception e){
            logger.error("设置缓存失败",e);
        }
        return map;
    }

    /***
     * 设置缓存 ，并将list转为map
     * @param key
     * @param fieldName
     * @param list
     * @param <T>
     */
    public static <T> void setRedisToMapList(String key,String fieldName,List<T> list){
        Map<String,List<T>> map = new HashMap<>(16);
        try {
            for(Object o:list){
                String value =  ConvertUtil.null2String(ReflectionUtils.getFieldValue(o,fieldName));
                if(map.containsKey(value)){
                    List<T> list1 = map.get(value);
                    list1.add((T)o);
                }else{
                    List<T> list1 = new ArrayList<>();
                    list1.add((T)o);
                    map.put(value,list1);
                }
            }
            setObject(key,map);
        }catch (Exception e){
            logger.error("设置缓存失败",e);
        }
    }

    /***
     * 将缓存map转为list
     * @param key
     */
    public static List<T> getRedisToList(String key){
        List<T> list = new ArrayList<>();
        try {
            Map<String,T> map = (Map<String, T>) getObject(key);
            for(String code:map.keySet()){
                list.add(map.get(code));
            }
        } catch (Exception e) {
            logger.error("缓存转list失败",e);
        }
        return  list;
    }
    /**
     *map:要赋的属性值集合

     */
    public static Object getByReflect(Class<?> model, Map map)throws Exception {
        Object object = new Object();
        if (model != null) {
            Field[] field = model.getDeclaredFields();
            object = model.newInstance();
            Method m = null;
            for (int i = 1; i <field.length ; i++) {
                String realName = field[i].getName();
                Object value = null;
                String name = realName.substring(0, 1).toUpperCase() + realName.substring(1);
                String propertyTypeName = field[i].getGenericType().toString();
                if(map.containsKey(realName)){
                    if (propertyTypeName.equals(String.class.getName())) {
                        m = model.getDeclaredMethod("set" + name, String.class);
                        value = (String)map.get(realName);
                    }else if (propertyTypeName.equals(int.class.getName())
                            || propertyTypeName.equals(Integer.class.getName())) {
                        m = model.getDeclaredMethod("set" + name, Integer.class);
                        value = (Integer)(map.get(realName));
                    }else if(propertyTypeName.equals(long.class.getName())
                            || propertyTypeName.equals(Long.class.getName())){
                        m = model.getDeclaredMethod("set" + name, Long.class);
                        value = (Long)map.get(realName);
                    }else if (propertyTypeName.equals(short.class.getName())
                            || propertyTypeName.equals(Short.class.getName())) {
                        m = model.getDeclaredMethod("set" + name, Short.class);
                        value = (Short)map.get(realName);
                    }else if (propertyTypeName.equals(float.class.getName())
                            || propertyTypeName.equals(Float.class.getName())) {
                        m = model.getDeclaredMethod("set" + name, Float.class);
                        value = (Float)map.get(realName);
                    }else if (propertyTypeName.equals(double.class.getName())
                            || propertyTypeName.equals(Double.class.getName())) {
                        m = model.getDeclaredMethod("set" + name, Double.class);
                        value = (Double)map.get(realName);
                    }else if (propertyTypeName.equals(boolean.class.getName())
                            || propertyTypeName.equals(Boolean.class.getName())) {
                        m = model.getDeclaredMethod("set" + name, Boolean.class);
                        value = (Boolean)map.get(realName);
                    }
                }

                if (m != null) {
                    m.invoke(object, value);
                }
            }
        }
        return object;
    }
}
